//
// Created by luosong on 15/8/24.
// Copyright (c) 2015 CHANJET. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "CSPModel.h"

@class CSPTask;
@class CSPNetworkingRequest;
@class CSPRequestConfig;

FOUNDATION_EXPORT NSString *const CSPNetworkingErrorDomain;
typedef NS_ENUM(NSInteger, CSPNetworkingErrorType) {
    CSPNetworkingErrorUnknown,
    CSPNetworkingErrorCancelled
};

#pragma mark - CSPHTTPMethod

typedef NS_ENUM(NSInteger, CSPHTTPMethod) {
    CSPHTTPMethodUnknown,
    CSPHTTPMethodGET,
    CSPHTTPMethodHEAD,
    CSPHTTPMethodPOST,
    CSPHTTPMethodPUT,
    CSPHTTPMethodPATCH,
    CSPHTTPMethodDELETE
};

typedef NS_ENUM(NSInteger, CSPRequestSerializerType) {
    CSPRequestSerializerTypeHTTP = 0,
    CSPRequestSerializerTypeJSON,
};


typedef NS_ENUM(NSInteger, CSPRequestRetryType) {
    CSPRequestRetryTypeUnknown,
    CSPRequestRetryTypeShouldNotRetry,
    CSPRequestRetryTypeShouldRetry,
    CSPRequestRetryTypeShouldRefreshCredentialsAndRetry,
    CSPRequestRetryTypeShouldCorrectClockSkewAndRetry
};


FOUNDATION_EXPORT NSString *const CSPGeneralErrorDomain;

typedef NS_ENUM(NSInteger, CSPGeneralErrorType) {
    CSPGeneralErrorUnknown,
    CSPGeneralErrorRequestTimeTooSkewed,
    CSPGeneralErrorInvalidSignatureException,
    CSPGeneralErrorSignatureDoesNotMatch,
    CSPGeneralErrorRequestExpired,
    CSPGeneralErrorAuthFailure
};


typedef void (^CSPNetworkingUploadProgressBlock) (int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend);
typedef void (^CSPNetworkingDownloadProgressBlock) (int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite);
typedef void (^CSPNetworkingCompletionHandlerBlock)(id responseObject, NSError *error);

@interface NSString (CSPHTTPMethod)
+ (instancetype)csp_stringWithHTTPMethod:(CSPHTTPMethod)HTTPMethod;
@end


@protocol CSPRequestInterceptor <NSObject>
@required
- (CSPTask *)interceptRequest:(NSMutableURLRequest *)request;
@end


@protocol CSPURLRequestSerializer <NSObject>

@required
- (CSPTask *)validateRequest:(NSURLRequest *)request;
- (CSPTask *)serializeRequest:(NSMutableURLRequest *)request
                      headers:(NSDictionary *)headers
                   parameters:(NSDictionary *)parameters;

@end

@protocol CSPHTTPURLResponseSerializer <NSObject>

@required

- (BOOL)validateResponse:(NSHTTPURLResponse *)response
             fromRequest:(NSURLRequest *)request
                    data:(id)data
                   error:(NSError *__autoreleasing *)error;
- (id)responseObjectForResponse:(NSHTTPURLResponse *)response
                originalRequest:(NSURLRequest *)originalRequest
                 currentRequest:(NSURLRequest *)currentRequest
                           data:(id)data
                          error:(NSError *__autoreleasing *)error;

@end

@protocol CSPNetworkingRequestInterceptor <NSObject>

@required
- (CSPTask *)interceptRequest:(NSMutableURLRequest *)request;

@end

@protocol CSPNetworkingHTTPResponseInterceptor <NSObject>

@required
- (CSPTask *)interceptResponse:(NSHTTPURLResponse *)response
                          data:(id)data
               originalRequest:(NSURLRequest *)originalRequest
                currentRequest:(NSURLRequest *)currentRequest;

@end

@protocol CSPRequestRetryHandler <NSObject>


@required

@property (nonatomic, assign) uint32_t maxRetryCount;

- (CSPRequestRetryType)shouldRetry:(uint32_t)currentRetryCount
                             response:(NSHTTPURLResponse *)response
                                 data:(NSData *)data
                                error:(NSError *)error;

- (NSTimeInterval)timeIntervalForRetry:(uint32_t)currentRetryCount
                              response:(NSHTTPURLResponse *)response
                                  data:(NSData *)data
                                 error:(NSError *)error;

@end

@interface CSPNetworking : NSObject

- (instancetype)initWithConfiguration:(CSPRequestConfig *)configuration;

- (CSPTask *)sendRequest:(CSPNetworkingRequest *)request;

@end

@interface CSPRequest : CSPModel
@property (nonatomic, assign, readonly, getter = isCancelled) BOOL cancelled;
- (CSPTask *)cancel;
- (CSPTask *)pause;
@end